package rpc

import (
	"github.com/golang/protobuf/proto"
	"leaf/core/log"
	. "leaf/core/msg"
	"reflect"
)

type IServiceFilter interface {
	GetService(sid uint16) interface{}
}

type IRpcService interface {
	GetServiceName() string
}

type IServicRpcFilter interface {
	GetServicRpc() *ServicRpc
}

type RpcProcessor struct {
	handlers        map[string]map[string]*RpcHandler
	services        map[string]interface{}
	rpcHandlerInfos *RpcHandlerInfos
	serviceFilter   IServiceFilter

	rpcHandlers map[string]*RpcHandler
	serviceMap  map[reflect.Type]interface{}
}

var processer = NewRpcProcessor()

func NewRpcProcessor() *RpcProcessor {
	p := new(RpcProcessor)
	p.handlers = make(map[string]map[string]*RpcHandler)
	p.services = make(map[string]interface{})
	p.rpcHandlerInfos = &RpcHandlerInfos{
		Handlers: []*RpcHandlerInfo{},
	}
	p.rpcHandlers = make(map[string]*RpcHandler)
	p.serviceMap = make(map[reflect.Type]interface{})
	return p
}

func (p *RpcProcessor) GetService(t reflect.Type) interface{} {
	if s, ok := p.serviceMap[t]; ok {
		return s
	}
	return nil
}

func (p *RpcProcessor) RegisterService(s interface{}) {
	p.serviceMap[reflect.TypeOf(s)] = s
}

func (p *RpcProcessor) Register(servicType reflect.Type, requestMsg proto.Message, replyMsg proto.Message, methodStr string, method RpcMethod) {
	log.Release("Register rpc %v", methodStr)
	var requestType reflect.Type
	var requestId uint16
	if requestMsg != nil {
		requestType = reflect.TypeOf(requestMsg)
		requestId = GetMessageId(requestType)
		if requestId == 0 {
			log.Error("Register requestType:%v check message err", requestType)
			return
		}
	}

	var replyType reflect.Type
	var replyId uint16
	if replyMsg != nil {
		replyType = reflect.TypeOf(replyMsg)
		replyId = GetMessageId(replyType)
		if replyId == 0 {
			log.Error("Register replyType:%v check message err", replyType)
			return
		}
	}

	if _, ok := p.handlers[methodStr]; ok {
		log.Error("Register handle of %v exist", requestId)
		return
	}

	rpcHandler := new(RpcHandler)
	rpcHandler.Func = method
	rpcHandler.RequestId = requestId
	rpcHandler.RequestType = requestType
	rpcHandler.ReplyId = replyId
	rpcHandler.ReplyType = replyType
	rpcHandler.ServiceType = servicType

	p.rpcHandlers[methodStr] = rpcHandler
	p.rpcHandlerInfos.Handlers = append(p.rpcHandlerInfos.Handlers, &RpcHandlerInfo{
		Method:    proto.String(methodStr),
		RequestId: proto.Uint32(uint32(requestId)),
		ReplyId:   proto.Uint32(uint32(replyId)),
	})
}

func (p *RpcProcessor) GetHandler(method string) (interface{}, *RpcHandler) {
	var rpcHandler *RpcHandler
	var ok bool
	if rpcHandler, ok = p.rpcHandlers[method]; !ok {
		return nil, nil
	}

	if rpcHandler.ServiceType == nil {
		return nil, rpcHandler
	}

	var s interface{}
	if s, ok = p.serviceMap[rpcHandler.ServiceType]; !ok {
		return nil, nil
	} else {
		return s, rpcHandler
	}
}
